package io.potato.core.util;

import io.potato.core.exception.ReflectException;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;


/**
 * javabean工具类
 * 
 * @author longshangbo@163.com
 *
 * <p>2017年7月1日 下午2:27:04</p>
 */
public abstract class BeanUtils {

	/**
	 * 获取指定类所有的字段，包括父类中的所有字段
	 * 
	 * @param clazz 指定的类的class对象
	 * @return 所有字段
	 */
	public static List<Field> getAllFields(Class<?> clazz){
		List<Field> fields = new ArrayList<Field>();
		
		for(Class<?> c = clazz; c != Object.class; c = c.getSuperclass()){
			fields.addAll(Arrays.asList(c.getDeclaredFields()));
		}
		
		return fields;
	}
	
	/**
	 * 获取所有字段map集合
	 * 
	 * @param clazz Class类型
	 * @return 字段map
	 */
	public static Map<String, Field> getAllFieldMap(Class<?> clazz){
		Map<String, Field> fieldMap = new HashMap<String, Field>();
		
		for(Class<?> c = clazz; c != Object.class; c = c.getSuperclass()){
			for(Field field : c.getDeclaredFields()){
				fieldMap.put(field.getName(), field);
			}
		}
		
		return fieldMap;
	}
	
	/**
	 * 获取所有字段描述符map
	 * 
	 * @param Class类型
	 * @return 字段描述符map
	 */
	public static Map<String, PropertyDescriptor> getAllPropertyDescriptorMap(Class<?> clazz){
		Map<String, PropertyDescriptor> descriptorMap = new HashMap<String, PropertyDescriptor>();
		try {
			BeanInfo info = Introspector.getBeanInfo(clazz);

			for(PropertyDescriptor pd : info.getPropertyDescriptors()){
				descriptorMap.put(pd.getName(), pd);
			}
			
			return descriptorMap;
		} catch (IntrospectionException e) {
			throw new ReflectException(e);
		}
	}
	
	/**
	 * 获取字段的getter方法
	 * 
	 * @param clazz Class对象
	 * @param field 字段名
	 * @return getter方法
	 */
	public static Method getReadMethod(Class<?> clazz, String field) {
		try {
			return new PropertyDescriptor(field, clazz).getReadMethod();
		} catch (IntrospectionException e) {
			throw new ReflectException("Property [" + field + "] not exists.", e);
		}
	}
	
	/**
	 * 获取字段的setter方法
	 * 
	 * @param field 字段名
	 * @param clazz Class对象
	 * @return getter方法
	 */
	public static Method getWriteMethod(Class<?> clazz, String field) {
		try {
			return new PropertyDescriptor(field, clazz).getWriteMethod();
		} catch (IntrospectionException e) {
			throw new ReflectException("Property [" + field + "] not exists.", e);
		}
	}
	
	/**
	 * 设置字段值
	 * 
	 * @param obj 指定对象
	 * @param fieldName 字段名称
	 * @param value 字段值
	 */
	public static void setFieldValue(Object obj, String fieldName, Object value) {
		AssertUtils.isNotNull(obj);
		AssertUtils.isNotBlank(fieldName);
		Method writeMethod = getWriteMethod(obj.getClass(), fieldName);
		
		try {
			writeMethod.invoke(obj, value);
		} catch (Exception e) {
			throw new ReflectException("Property [" + fieldName + "] setter invoke failed.", e);	
		}
	}
	
	/**
	 * 获取字段值
	 * 
	 * @param obj 指定对象
	 * @param fieldName 字段名称
	 * @return 字段值
	 */
	public static Object getFieldValue(Object obj, String fieldName) {
		AssertUtils.isNotNull(obj);
		AssertUtils.isNotBlank(fieldName);
		Method readMethod = getReadMethod(obj.getClass(), fieldName);
		
		try {
			return readMethod.invoke(obj);
		} catch (Exception e) {
			throw new ReflectException("Property [" + fieldName + "] getter invoke failed.", e);	
		}
	}
	
	/**
	 * 反射创建对象实例
	 * 
	 * @param clazz Class对象
	 * @return 对象实例
	 */
	public static <T> T instantiateClass(Class<T> clazz) {
		return org.springframework.beans.BeanUtils.instantiateClass(clazz);
	}
	
}
